package org.road0329.tools.proto_parse_tool.utils;

import org.road0329.tools.proto_parse_tool.enums.DateFormatEnum;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class ProtocolGW_09Util {

    public static String getDADTFrame(int pn, int fn) {
        int da2 = 0;
        if (pn > 0) {
            da2 = (pn - 1) / 8 + 1;
        }
        int da1 = (pn - 1) % 8;
        int dt2 = (fn - 1) / 8;
        int dt1 = (fn - 1) % 8;
        String pnfn = String.format("%02X%02X%02X%02X", da2, (byte) (1 << da1), dt2, (byte) (1 << dt1));
        return pnfn;
    }

    public static String getDTDAFrame(int pn, int fn) {
        int da2 = 0;
        if (pn > 0) {
            da2 = (pn - 1) / 8 + 1;
        }
        int da1 = (pn - 1) % 8;
        int dt2 = (fn - 1) / 8;
        int dt1 = (fn - 1) % 8;
        String pnfn = String.format("%02X%02X%02X%02X", dt2, (byte) (1 << dt1), da2, (byte) (1 << da1));
        if(pn < 0) {//当pn=-1时，则DA1=FFH、DA2=00H，表示所有有效测量点（不含p0）。
            pnfn = String.format("%02X%02X00FF", dt2, (byte) (1 << dt1));
        }
        return pnfn;
    }

    public static short getDA(String dadt) throws Exception {
        if (dadt == null || dadt.length() != 8) {
            throw new Exception("DADT数据表示非法...GW规约.");
        }
        byte[] buf = ProtocolUtils.StringToHex(dadt);
        short pn = ProtocolUtils.byteToShort(buf[3], buf[2]);
        return pn;
    }

    public static short getDT(String dadt) throws Exception {
        if (dadt == null || dadt.length() != 8) {
            throw new Exception("DADT数据表示非法...GW规约.");
        }
        byte[] buf = ProtocolUtils.StringToHex(dadt);
        short fn = ProtocolUtils.byteToShort(buf[0], buf[1]);
        return fn;
    }

    public static String pickA15(Date date) {
        String dateA15 = "";
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        dateA15 = dateA15 + String.valueOf(cal.get(Calendar.YEAR)).substring(2);// 年
        dateA15 = dateA15 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.MONTH) + 1), 2, "0");// 月
        dateA15 = dateA15 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.DAY_OF_MONTH)), 2, "0");// 日
        dateA15 = dateA15 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.HOUR_OF_DAY)), 2, "0");// 时
        dateA15 = dateA15 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.MINUTE)), 2, "0");// 分
        return dateA15;
    }

    public static String pickA29(Date date) {
        String dateA15 = "";
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        dateA15 = dateA15 + String.valueOf(cal.get(Calendar.YEAR)).substring(2);// 年
        dateA15 = dateA15 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.MONTH) + 1), 2, "0");// 月
        dateA15 = dateA15 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.DAY_OF_MONTH)), 2, "0");// 日
        dateA15 = dateA15 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.HOUR_OF_DAY)), 2, "0");// 时
        dateA15 = dateA15 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.MINUTE)), 2, "0");// 分
        dateA15 = dateA15 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.SECOND)), 2, "0");// 分
        return dateA15;
    }

    public static String pickA20(Date date) {
        String dateA20 = "";
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        dateA20 = dateA20 + String.valueOf(cal.get(Calendar.YEAR)).substring(2);// 年
        dateA20 = dateA20 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.MONTH) + 1), 2, "0");// 月
        dateA20 = dateA20 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.DAY_OF_MONTH)), 2, "0");// 日
        return dateA20;
    }

    public static String pickA21(Date date) {
        String dateA20 = "";
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        dateA20 = dateA20 + String.valueOf(cal.get(Calendar.YEAR)).substring(2);// 年
        dateA20 = dateA20 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.MONTH) + 1), 2, "0");// 月
        return dateA20;
    }

    public static String parseA15(byte[] data, int index) {
        if (ProtocolUtils.Unsignd(data[index]) == 0xEE) {
            return "无此项;";
        }
        Date dataTime = ProtocolGW_09Util.parseDateTime(data, index, DateFormatEnum.A15);
        return DateUtil.DateToStr(dataTime, DateUtil.TIME_NO_SEC);
    }

    public static String parseA17(byte[] data, int index) {
        if (ProtocolUtils.Unsignd(data[index]) == 0xEE) {
            return "无此项;";
        }
        Date dataTime = ProtocolGW_09Util.parseDateTime(data, index, DateFormatEnum.A17);
        return DateUtil.DateToStr(dataTime, DateUtil.MONTH_DATE_NO_SEC);
    }

    public static String parseA18(byte[] data, int index) {
        if (ProtocolUtils.Unsignd(data[index]) == 0xEE) {
            return "无此项;";
        }
        Calendar date = Calendar.getInstance();
        date.set(Calendar.MILLISECOND, 0);
        date.set(Calendar.SECOND, 0);
        if (data == null || data.length - index < 3) {
            return "无此项;";
        }
        date.set(Calendar.MINUTE, ProtocolUtils.BCDToHex(data[index]));
        date.set(Calendar.HOUR_OF_DAY, ProtocolUtils.BCDToHex(data[index + 1]));
        date.set(Calendar.DAY_OF_MONTH, ProtocolUtils.BCDToHex(data[index + 2]));
        return DateUtil.DateToStr(date.getTime(), DateUtil.DAY_HOUR_MIN_CN);
    }

    public static String parseA20(byte[] data, int index) {
        if (ProtocolUtils.Unsignd(data[index]) == 0xEE) {
            return "无此项;";
        }

        Date dataTime = ProtocolGW_09Util.parseDateTime(data, index, DateFormatEnum.A20);
        return DateUtil.DateToStr(dataTime, DateUtil.TIME_SHORT);
    }

    public static String parseA21(byte[] data, int index) {
        if (ProtocolUtils.Unsignd(data[index]) == 0xEE) {
            return "无此项;";
        }

        Date dataTime = ProtocolGW_09Util.parseDateTime(data, index, DateFormatEnum.A21);
        return DateUtil.DateToStr(dataTime, DateUtil.MONTHTIME);
    }

    public static String pickA1(Date date) {
        String dateA1 = "";
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        dateA1 = dateA1 + String.valueOf(cal.get(Calendar.YEAR)).substring(2);// 年
        int week = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (week < 1) {
            week = 1;
        }
        int left = (week << 1) + (cal.get(Calendar.MONTH) + 1) / 10;
        int right = (cal.get(Calendar.MONTH) + 1) % 10;
        dateA1 = dateA1 + (NumberUtil.num2PadString(left, 16, 1, "0") + NumberUtil.num2PadString(right, 16, 1, "0"));
        dateA1 = dateA1 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.DAY_OF_MONTH)), 2, "0");// 日
        dateA1 = dateA1 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.HOUR_OF_DAY)), 2, "0");// 时
        dateA1 = dateA1 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.MINUTE)), 2, "0");// 分
        dateA1 = dateA1 + StringUtil.AddjustLength(String.valueOf(cal.get(Calendar.SECOND)), 2, "0");// 秒
        return dateA1;
    }

    public static String pickA7(BigDecimal data) {
        if (data == null) {
            return "0000";
        }
        return pickNumberBase2(data, 3, 1);
    }

    public static String pickA10(BigDecimal data) {
        if (data == null) {
            return "000000";
        }
        return pickNumberBase2(data, 6, 0);
    }

    //xxx.x
    public static String pickA5(BigDecimal data) {
        if (data == null) {
            return "0000";
        }
        return pickNumberBase(data, 3, 1);
    }

    //xx.xx
    public static String pickA28(BigDecimal data) {
        if (data == null) {
            return "0000";
        }
        return pickNumberBase2(data, 2, 2);
    }

    public static String pickA8(BigDecimal data) {
        if (data == null) {
            return "0000";
        }
        return pickNumberBase2(data, 4, 0);
    }

    public static String pickEsamPrice(BigDecimal data) {//1.0为00010000 即4位小数
        if (data == null) {
            return "00000000";
        }
        return pickNumberBase2(data, 4, 4);
    }

    public static String pickEsamEnergy(BigDecimal data) {//1.0为00000100 即2位小数
        if (data == null) {
            return "00000000";
        }
        return pickNumberBase2(data, 6, 2);
    }

    // 无正负
    public static String pickNumberBase2(BigDecimal data, int intlen, int declen) {
        String dataString = "";
        String numString = "";
        numString = String.valueOf(data.toString());
        int pointpos = numString.indexOf(".");
        String intpart = pointpos == -1 ? numString : numString.substring(0, pointpos);
        String decpart = StringUtil.AddjustLengthBack(pointpos == -1 ? "0" : numString.substring(pointpos + 1), declen, "0");
        intpart = StringUtil.AddjustLength(intpart, intlen, "0");
        dataString = StringUtil.AddjustLength(intpart + decpart, intlen + declen, "0");
        return dataString;
    }

    // 有正负
    public static String pickNumberBase(BigDecimal data, int intlen, int declen) {
        String dataString = "";
        String flag = "0";
        String numString = "";
        if (data.compareTo(BigDecimal.ZERO) < 0) {// 去除负数
            flag = "1";
            numString = String.valueOf(data.toString()).substring(1);
        } else {
            numString = String.valueOf(data.toString());
        }
        int pointpos = numString.indexOf(".");
        String intpart = pointpos == -1 ? numString : numString.substring(0, pointpos);
        String decpart = StringUtil.AddjustLengthBack(pointpos == -1 ? "0" : numString.substring(pointpos + 1), declen, "0");
        intpart = StringUtil.AddjustLength(intpart, intlen, "0");
        String high = flag + StringUtil.numStr2PadString(intpart.substring(0, 1), 2, 3, "0");
        dataString = StringUtil.AddjustLength(Integer.toHexString(Integer.parseInt(high, 2)) + intpart.substring(1) + decpart, intlen + declen, "0");

        return dataString;
    }

    public static String pickA23(BigDecimal data) {
        if (data == null) {
            return "000000";
        }
        return pickNumberBase2(data, 2, 4);
    }

    public static String pickA25(BigDecimal data) {
        if (data == null) {
            return "000000";
        }
        return pickNumberBase(data, 3, 3);
    }

    public static Date parseA1(byte[] byteValue, int index) {
        Calendar date = Calendar.getInstance();
        date.set(Calendar.MILLISECOND, 0);
        date.set(Calendar.SECOND, 0);
        if (byteValue == null || byteValue.length - index < 6) {
            return null;
        }
        date.set(Calendar.SECOND, ProtocolUtils.BCDToHex(byteValue[index]));
        date.set(Calendar.MINUTE, ProtocolUtils.BCDToHex(byteValue[index + 1]));
        date.set(Calendar.HOUR_OF_DAY, ProtocolUtils.BCDToHex(byteValue[index + 2]));
        date.set(Calendar.DAY_OF_MONTH, ProtocolUtils.BCDToHex(byteValue[index + 3]));
        date.set(Calendar.MONTH, ProtocolUtils.BCDToHex((byte) (byteValue[index + 4] & 0x1F)) - 1);
        date.set(Calendar.YEAR, ProtocolUtils.BCDToHex(byteValue[index + 5]) + 2000);
        return date.getTime();
    }

    public static BigDecimal parseA12(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 6) {
            return null;
        }
        String value = String.format("%02X%02X%02X%02X%02X%02X", ProtocolUtils.Unsignd(byteValue[index + 5]), ProtocolUtils.Unsignd(byteValue[index + 4]),
                ProtocolUtils.Unsignd(byteValue[index + 3]), ProtocolUtils.Unsignd(byteValue[index + 2]), ProtocolUtils.Unsignd(byteValue[index + 1]),
                ProtocolUtils.Unsignd(byteValue[index]));
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static String parseA3(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 4 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return "无此项";
        }
        String value = String.format("%s%01X%02X%02X%02X", (byteValue[index + 3] & 0x10) == 0x10 ? "-" : "", ProtocolUtils.Unsignd((byte) (byteValue[index + 3] & 0x0F)),
                ProtocolUtils.Unsignd(byteValue[index + 2]), ProtocolUtils.Unsignd(byteValue[index + 1]), ProtocolUtils.Unsignd(byteValue[index]));
        String unit = "";
        if ((byteValue[index + 3] & 0x40) == 0x40) {
            unit = "kWh(厘)";
        } else {
            unit = "MWh(元)";
        }
        return ProtocolUtils.isNum(value) ? (new BigDecimal(value).toString() + unit) : "无此项";
    }

    public static BigDecimal parseA9(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 3 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%s%02X.%02X%02X", (byteValue[index + 2] & 0x80) == 0x80 ? "-" : "", ProtocolUtils.Unsignd((byte) (byteValue[index + 2] & 0x7F)),
                ProtocolUtils.Unsignd(byteValue[index + 1]), ProtocolUtils.Unsignd(byteValue[index]));
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA27(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 4 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }

        String value = String.format("%02X%02X%02X%02X", ProtocolUtils.Unsignd(byteValue[index + 3]), ProtocolUtils.Unsignd(byteValue[index + 2]),
                ProtocolUtils.Unsignd(byteValue[index + 1]), ProtocolUtils.Unsignd(byteValue[index]));
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA5(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 2 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }

        String value = String.format("%s%X.%01X", (byteValue[index + 1] & 0x80) == 0x80 ? "-" : "", (byteValue[index + 1] & 0x7F) * 0x10 + ((byteValue[index] >> 4) & 0x0F),
                byteValue[index] & 0x0F);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA6(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 2 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }

        String value = String.format("%s%X.%02X", (byteValue[index + 1] & 0x80) == 0x80 ? "-" : "", ProtocolUtils.Unsignd(byteValue[index + 1]),
                ProtocolUtils.Unsignd(byteValue[index]));
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA7(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 2 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%X.%01X", byteValue[index + 1] * 0x10 + ((byteValue[index] >> 4) & 0x0F), byteValue[index] & 0x0F);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA8(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 2 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%02X%02X", byteValue[index + 1], byteValue[index]);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA10(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 3 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%02X%02X%02X", byteValue[index + 2], byteValue[index + 1], byteValue[index]);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA23(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 3 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%X.%02X%02X", byteValue[index + 2], byteValue[index + 1], byteValue[index]);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA13(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 4 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%X%02X.%02X%02X", byteValue[index + 3], byteValue[index + 2], byteValue[index + 1], byteValue[index]);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA2(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 2 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        int power = 4 - (byteValue[index + 1] >> 5);
        int plusminus = (byteValue[index + 1] & 0x10) >> 4;
        String value = String.format((plusminus == 0 ? "" : "-") + "%02X%02X", (byteValue[index + 1] & 0x0F), byteValue[index]);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value).multiply(BigDecimal.valueOf(Math.pow(10, power))) : null;
    }

    public static BigDecimal parseA4(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 1 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        int floating = (byteValue[index] >> 7);
        String value = String.format((floating == 0 ? "" : "-") + "%02X", (byteValue[index] & 0x7F));
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA25(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 3 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%s%X.%01X%02X", (byteValue[index + 2] & 0x80) == 0x80 ? "-" : "", (byteValue[index + 2] & 0x7F) * 0x10 + ((byteValue[index + 1] >> 4) & 0x0F),
                byteValue[index + 1] & 0x0F, byteValue[index]);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA14(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 5 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%X%02X%02X.%02X%02X", byteValue[index + 4], byteValue[index + 3], byteValue[index + 2], byteValue[index + 1], byteValue[index]);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA11(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 4 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%X%02X%02X.%02X", byteValue[index + 3], byteValue[index + 2], byteValue[index + 1], byteValue[index]);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA220(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 5 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%X%02X%02X.%02X", byteValue[index + 4], byteValue[index + 3], byteValue[index + 2], byteValue[index + 1]);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA22(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 1 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%01X.%01X", (byteValue[index] >> 4), (byteValue[index] & 0x0F));
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA30(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 5) {
            return null;
        }
        int unit = byteValue[index];

        String value = String.format("%02X%02X.%02X%02X", ProtocolUtils.Unsignd(byteValue[index + 4]), ProtocolUtils.Unsignd(byteValue[index + 3]),
                ProtocolUtils.Unsignd(byteValue[index + 2]), ProtocolUtils.Unsignd(byteValue[index + 1]));
        if (ProtocolUtils.isNum(value) == false) {
            return null;
        }
        BigDecimal decValue = new BigDecimal(value);
        if (unit == 0x02) { // wh
            decValue = decValue.divide(new BigDecimal(1000));
        } else if (unit == 0x05) { // kWh

        } else if (unit == 0x08) {
            decValue = decValue.multiply(new BigDecimal(1000));
        } else if (unit == 0x0A) {
            decValue = decValue.multiply(new BigDecimal(100000));
        } else if (unit == 0x01) { // J
            decValue = decValue.divide(new BigDecimal(1000));
        } else if (unit == 0x0B) {

        } else if (unit == 0x0E) {
            decValue = decValue.multiply(new BigDecimal(1000));
        } else if (unit == 0x11) {
            decValue = decValue.multiply(new BigDecimal(1000000));
        } else if (unit == 0x13) {
            decValue = decValue.multiply(new BigDecimal(100000000));
        } else if (unit == 0x14) { // w
            decValue = decValue.divide(new BigDecimal(1000));
        } else if (unit == 0x17) {

        } else if (unit == 0x1A) {
            decValue = decValue.multiply(new BigDecimal(1000));
        } else if (unit == 0x29) { // L
            decValue = decValue.divide(new BigDecimal(1000));
        } else if (unit == 0x2C) {

        } else if (unit == 0x32) { // L/h
            decValue = decValue.divide(new BigDecimal(1000));
        } else if (unit == 0x35) {

        }
        return decValue;
    }

    public static String parseA32(byte[] data, int index) {
        if (ProtocolUtils.Unsignd(data[index]) == 0xEE || ProtocolUtils.Unsignd(data[index]) == 0xFF) {
            return "无此项;";
        }
        Calendar date = Calendar.getInstance();
        date.set(Calendar.MILLISECOND, 0);
        date.set(Calendar.SECOND, 0);
        if (data == null || data.length - index < 7) {
            return "无此项;";
        }
        date.set(Calendar.SECOND, ProtocolUtils.BCDToHex(data[index]));
        date.set(Calendar.MINUTE, ProtocolUtils.BCDToHex(data[index + 1]));
        date.set(Calendar.HOUR_OF_DAY, ProtocolUtils.BCDToHex(data[index + 2]));
        date.set(Calendar.DAY_OF_MONTH, ProtocolUtils.BCDToHex(data[index + 3]));
        date.set(Calendar.MONTH, ProtocolUtils.BCDToHex(data[index + 4]) - 1);
        date.set(Calendar.YEAR, Integer.parseInt(String.format("%02X%02X", data[index + 6], data[index + 5])));
        return DateUtil.DateToStr(date.getTime(), DateUtil.TIME_LONG);
    }

    public static BigDecimal parseA31(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 3 || ProtocolUtils.Unsignd(byteValue[index]) == 0xEE) {
            return null;
        }
        String value = String.format("%X%02X.%02X", byteValue[index + 2], byteValue[index + 1], byteValue[index]);
        return ProtocolUtils.isNum(value) ? new BigDecimal(value) : null;
    }

    public static BigDecimal parseA29(byte[] byteValue, int index) {
        if (byteValue == null || byteValue.length < index + 5) {
            return null;
        }
        int unit = byteValue[index];

        String value = String.format("%02X%02X%02X.%02X", ProtocolUtils.Unsignd(byteValue[index + 4]), ProtocolUtils.Unsignd(byteValue[index + 3]),
                ProtocolUtils.Unsignd(byteValue[index + 2]), ProtocolUtils.Unsignd(byteValue[index + 1]));
        if (ProtocolUtils.isNum(value) == false) {
            return null;
        }
        BigDecimal decValue = new BigDecimal(value);
        if (unit == 0x02) { // wh
            decValue = decValue.divide(new BigDecimal(1000));
        } else if (unit == 0x05) { // kWh

        } else if (unit == 0x08) {
            decValue = decValue.multiply(new BigDecimal(1000));
        } else if (unit == 0x0A) {
            decValue = decValue.multiply(new BigDecimal(100000));
        } else if (unit == 0x01) { // J
            decValue = decValue.divide(new BigDecimal(1000));
        } else if (unit == 0x0B) {

        } else if (unit == 0x0E) {
            decValue = decValue.multiply(new BigDecimal(1000));
        } else if (unit == 0x11) {
            decValue = decValue.multiply(new BigDecimal(1000000));
        } else if (unit == 0x13) {
            decValue = decValue.multiply(new BigDecimal(100000000));
        } else if (unit == 0x14) { // w
            decValue = decValue.divide(new BigDecimal(1000));
        } else if (unit == 0x17) {

        } else if (unit == 0x1A) {
            decValue = decValue.multiply(new BigDecimal(1000));
        } else if (unit == 0x29) { // L
            decValue = decValue.divide(new BigDecimal(1000));
        } else if (unit == 0x2C) {

        } else if (unit == 0x32) { // L/h
            decValue = decValue.divide(new BigDecimal(1000));
        } else if (unit == 0x35) {

        }
        return decValue;
    }

    public static void main(String [] args) {
//        String result= ProtocolGW_09Util.getDTDAFrame(-1, 2);
//        System.out.println(result);
//        String message = "2C 74 86 00 00";
//        message = message.replaceAll(" ","");
//        message = ProtocolUtils.reverse(message, message.length());
//        byte[] bytes = ProtocolUtils.StringToHex(message);
//
//        BigDecimal value = parseA29(bytes, 0);
//        System.out.println(value);

        byte da2= 0x01;
        byte da1=(byte)0x08;
        System.out.println("pn:"+ getPnFromDA(da2,da1));
//
        byte dt2 = 0x06;
        byte dt1 = 0x20;
        System.out.println("fn:"+ getFnFromDT(dt2,dt1));

        System.out.println(getDTDAFrame(4,55));



    }

    public static Integer getPnFromDA(byte da2, byte da1) {
        Integer pn = 0;
        for (int k = 0; k < 8; k++) {
            if ((da1 & 0x01) == 1) {
                pn = (da2 - 1) * 8 + k + 1;
                break;
            }
            da1 >>= 1;
        }
        return pn;
    }

    public static List<Integer> getPnListFromDA(byte da2, byte da1) {
        List<Integer> pnList = new ArrayList<>(8);
        Integer pn = 0;
        for (int k = 0; k < 8; k++) {
            if ((da1 & 0x01) == 1) {
                pn = (da2 - 1) * 8 + k + 1;
                pnList.add(pn);
            }
            da1 >>= 1;
        }
        return pnList;
    }

    public static int getFnFromDT(byte dt2, byte dt1) {
        for (int k = 0; k < 8; k++) {
            if ((dt1 & 0x01) == 1) {
                return (k + 1) + 8 * dt2;
            }
            dt1 >>= 1;
        }
        return 0;
    }

    public static Date parseDateTime(byte[] byteValue, int index, DateFormatEnum dt) {
        Calendar date = Calendar.getInstance();
        date.set(Calendar.MILLISECOND, 0);
        date.set(Calendar.SECOND, 0);
        if (dt.equals(DateFormatEnum.A15)) {
            if (byteValue == null || byteValue.length - index < 5) {
                return null;
            }
            if (ProtocolUtils.BCDToHex(byteValue[index + 3]) < 1 || ProtocolUtils.BCDToHex(byteValue[index + 4]) < 1) {
                return null;
            }
            date.set(Calendar.MINUTE, ProtocolUtils.BCDToHex(byteValue[index]));
            date.set(Calendar.HOUR_OF_DAY, ProtocolUtils.BCDToHex(byteValue[index + 1]));
            date.set(Calendar.DAY_OF_MONTH, ProtocolUtils.BCDToHex(byteValue[index + 2]));
            date.set(Calendar.MONTH, ProtocolUtils.BCDToHex(byteValue[index + 3]) - 1);
            date.set(Calendar.YEAR, ProtocolUtils.BCDToHex(byteValue[index + 4]) + 2000);
            return date.getTime();
        } else if (dt.equals(DateFormatEnum.A17)) {
            if (byteValue == null || byteValue.length - index < 4) {
                return null;
            }
            if (ProtocolUtils.BCDToHex(byteValue[index + 3]) < 1) {
                return null;
            }
            date.set(Calendar.MINUTE, ProtocolUtils.BCDToHex(byteValue[index]));
            date.set(Calendar.HOUR_OF_DAY, ProtocolUtils.BCDToHex(byteValue[index + 1]));
            date.set(Calendar.DAY_OF_MONTH, ProtocolUtils.BCDToHex(byteValue[index + 2]));
            date.set(Calendar.MONTH, ProtocolUtils.BCDToHex(byteValue[index + 3]) - 1);
            return date.getTime();
        } else if (dt.equals(DateFormatEnum.A20)) {
            if (byteValue == null || byteValue.length - index < 3) {
                return null;
            }
            if (ProtocolUtils.BCDToHex(byteValue[index + 1]) < 1 || ProtocolUtils.BCDToHex(byteValue[index + 2]) < 1) {
                return null;
            }
            date.set(Calendar.MINUTE, 0);
            date.set(Calendar.HOUR_OF_DAY, 0);
            date.set(Calendar.DAY_OF_MONTH, ProtocolUtils.BCDToHex(byteValue[index]));
            date.set(Calendar.MONTH, ProtocolUtils.BCDToHex(byteValue[index + 1]) - 1);
            date.set(Calendar.YEAR, ProtocolUtils.BCDToHex(byteValue[index + 2]) + 2000);
            return date.getTime();
        } else if (dt.equals(DateFormatEnum.A21)) {
            if (byteValue == null || byteValue.length - index < 2) {
                return null;
            }
            date.set(Calendar.MINUTE, 0);
            date.set(Calendar.HOUR_OF_DAY, 0);
            date.set(Calendar.DAY_OF_MONTH, 1);
            date.set(Calendar.MONTH, ProtocolUtils.BCDToHex(byteValue[index + 1]) - 1);
            date.set(Calendar.YEAR, ProtocolUtils.BCDToHex(byteValue[index + 2]) + 2000);
            return date.getTime();
        } else {
            return null;
        }
    }
}
